package org.grc.app.z_project.z_framework.helper;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.grc.app.z_project.z_framework.annotation.Aspect;
import org.grc.app.z_project.z_framework.annotation.Transaction;
import org.grc.app.z_project.z_framework.proxy.AspectProxy;
import org.grc.app.z_project.z_framework.proxy.Proxy;
import org.grc.app.z_project.z_framework.proxy.ProxyManager;
import org.grc.app.z_project.z_framework.proxy.TransactionProxy;
import org.grc.app.z_project.z_framework.util.ReflectionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/*
 * AopHelper需要获取所有目标类和及其被拦截的切面类实例，
 * 并通过 ProxyManager#createProxy方法来创建代理对象，最后将其放入 Bean Map中。
 */

/**
 * 方法拦截助手类
 * 
 * @author grc
 * @since 1.0-SNAPSHOT
 */
public class AopHelper {

	private static final Logger LOGGER = LoggerFactory.getLogger(AopHelper.class);

	static {
		try {
			Map<Class<?>, Set<Class<?>>> proxyMap = createProxyMap();
			Map<Class<?>, List<Proxy>> targetMap = createTargetMap(proxyMap);
			for (Map.Entry<Class<?>, List<Proxy>> targetEntry : targetMap.entrySet()) {
				Class<?> targetClass = targetEntry.getKey();
				List<Proxy> proxyList = targetEntry.getValue();
				Object proxy = ProxyManager.createProxy(targetClass, proxyList);
				BeanHelper.setBean(targetClass, proxy);
			}
		} catch (Exception e) {
			LOGGER.error("aop failure", e);
		}
	}
	
	/*
	 * 
	 */
	private static Set<Class<?>> createTargetClassSet (Aspect aspect) 
	throws Exception {
		Set<Class<?>> targetClassSet = new HashSet<Class<?>>();
		Class<? extends Annotation> annotation = aspect.value();
		// !annotation.equals(Aspect.class) -> Aspect注解里的类不能为 Aspect
		if (annotation != null && !annotation.equals(Aspect.class)) {
			targetClassSet.addAll(ClassHelper.getClassSetByAnnotation(annotation));
		}
		return targetClassSet;
	}
	
	/*
	 * 获取代理类和目标类集合之间的映射关系，一个代理类可以对应一个或多个目标类。
	 * 这里的代理类指的是切面类。
	 */
	private static Map<Class<?>, Set<Class<?>>> createProxyMap () 
	throws Exception {
		// 代理类需要扩展 AspectProxy抽象类，还需要被Aspect注解。
		Map<Class<?>, Set<Class<?>>> proxyMap = new HashMap<Class<?>, Set<Class<?>>>();
		addAspectProxy(proxyMap);
		addTransactionProxy(proxyMap);
		return proxyMap;
	}
	
	private static void addAspectProxy (Map<Class<?>, Set<Class<?>>> proxyMap)
	throws Exception {
		// AspectProxy类的集合
		Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class);
		for (Class<?> proxyClass : proxyClassSet) {
			// 确保被Aspect注解
			if (proxyClass.isAnnotationPresent(Aspect.class)) {
				Aspect aspect = proxyClass.getAnnotation(Aspect.class);
				Set<Class<?>> targetClassSet = createTargetClassSet(aspect);
				proxyMap.put(proxyClass, targetClassSet);
			}
		}
	}
	
	private static void addTransactionProxy (Map<Class<?>, Set<Class<?>>> proxyMap) 
	throws Exception {
		// 事务只能在service类里目前来说
		Set<Class<?>> serviceClassSet = ClassHelper.getServiceClassSet();
		proxyMap.put(TransactionProxy.class, serviceClassSet);
	}
	
	private static Map<Class<?>, List<Proxy>> createTargetMap (Map<Class<?>, Set<Class<?>>> proxyMap) 
	throws Exception {
		Map<Class<?>, List<Proxy>> targetMap = new HashMap<Class<?>, List<Proxy>>();
		for (Map.Entry<Class<?>, Set<Class<?>>> proxyEntry : proxyMap.entrySet()) {
			Class<?> proxyClass = proxyEntry.getKey();
			Set<Class<?>> targetClassSet = proxyEntry.getValue();
			for (Class<?> targetClass : targetClassSet) {
//				Proxy proxy = (Proxy) proxyClass.newInstance();
				Proxy proxy = (Proxy) ReflectionUtil.newInstance(proxyClass);
				if (targetMap.containsKey(targetClass)) {
					targetMap.get(targetClass).add(proxy);
				} else {
					List<Proxy> proxyList = new ArrayList<Proxy>();
					proxyList.add(proxy);
					targetMap.put(targetClass, proxyList);
				}
			}
		}
		return targetMap;
	}
}
